#include "pedumperlearn.h"
#include <Windows.h>
#include <stdio.h>

// QQQ
// validiation
// - validation (signiture always ...)

PVOID RelativeVirtualAddressToFileAddress(DWORD RelativeVirtualAddress, PIMAGE_SECTION_HEADER Sections, DWORD NumberOfSections, DWORD FileZero)
{
    DWORD i;
    DWORD fileAddress;

    fileAddress = 0;

	for (i = 0; i < NumberOfSections; ++i)
	{
		if (Sections[i].VirtualAddress <= RelativeVirtualAddress && 
			(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize) > RelativeVirtualAddress)
		{
			// fount the section
			fileAddress = Sections[i].PointerToRawData + (RelativeVirtualAddress - Sections[i].VirtualAddress);
            break;
            // QQQ
			// CHECK if it is valid
		}
	}

	// no hit?

    return (PVOID)(fileAddress + FileZero);
}



BOOLEAN OpenAndMapExecutableFile(PWCHAR FileName, PEXECUTABLEFILE PEFile)
{
    HANDLE hFile;
    HANDLE hMap;
    BOOLEAN bFail;
    PVOID ptr;
    DWORD size;
    DWORD lastError;

    hFile = INVALID_HANDLE_VALUE;
    hMap = NULL;
    bFail = FALSE;
    ptr = NULL;
    lastError = ERROR_SUCCESS;

	hFile = CreateFile(
		FileName,
		GENERIC_READ,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		bFail = TRUE;
		lastError = GetLastError();
		DebugLog("[ERROR] CreateFile failed with 0x%08x, on %S", lastError, FileName);
		goto finish;
	}

	hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
	if (hMap == NULL)
	{
		bFail = TRUE;
		lastError = GetLastError();
		DebugLog("[ERROR] CreateFileMapping failed with 0x%08x", lastError);
		goto finish;
	}

	ptr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
	if (ptr == NULL)
	{
		bFail = TRUE;
		lastError = GetLastError();
		DebugLog("[ERROR] MapViewOfFile failed with 0x%08x", lastError)
		goto finish;
	}

	{
		LARGE_INTEGER li;
		if (!GetFileSizeEx(hFile, &li))
		{
			bFail = TRUE;
			lastError = GetLastError();
			DebugLog("[ERROR] GetFileSizeEx failed with 0x%08x", lastError);
			goto finish;
		}

		size = li.LowPart;
	}

finish:
	if (bFail)
	{
		if (ptr != NULL)
		{
			if (UnmapViewOfFile(ptr))
			{
				DebugLog("[WARNING] UnmapViewOfFile failed with 0x%08x", GetLastError());
			}
		}

		if (hMap != NULL)
		{
			if (CloseHandle(hMap))
			{
				DebugLog("[WARNING] CloseHandle failed with 0x%08x", GetLastError());
			}
		}

		if (hFile != INVALID_HANDLE_VALUE)
		{
			if (!CloseHandle(hFile))
			{
				DebugLog("[WARNING] CloseHandle failed with 0x%08x", GetLastError());
			}
		}

		SetLastError(lastError);
	}
	else
	{
		PEFile->ZeroFileOffsetPointer = ptr;
		PEFile->FileSize = size;
		PEFile->HandleFile = hFile;
		PEFile->HandleMap = hMap;
	}

    return bFail;
}

BOOLEAN UnMapAndCloseExecutableFile(PEXECUTABLEFILE PEFile)
{
    if (PEFile->ZeroFileOffsetPointer != NULL)
    {
        if (UnmapViewOfFile(PEFile->ZeroFileOffsetPointer))
        {
            // QQQ
            // DebugLog("[ERROR]");
            return FALSE;
        }
    }
    if (PEFile->HandleMap != NULL)
    {
        if (CloseHandle(PEFile->HandleMap))
        {
            // QQQ
            // DebugLog("[ERROR]");
            return FALSE;
        }
    }

    if (PEFile->HandleFile != INVALID_HANDLE_VALUE)
    {
        if (!CloseHandle(PEFile->HandleFile))
        {
            // QQQ
            // DebugLog("[ERROR]");
            return FALSE;
        }
    }

    // oK
    return 1;
}

VOID PrintRawHeaders(PEXECUTABLEFILE PEFile)
{
	PIMAGE_DOS_HEADER idh;
	PIMAGE_NT_HEADERS inh;
	PIMAGE_SECTION_HEADER ishs;
	DWORD i;

	idh = (PIMAGE_DOS_HEADER)PEFile->ZeroFileOffsetPointer;

	if (idh->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", idh->e_magic, IMAGE_DOS_SIGNATURE);
		return;
	}
	printf("\nIMAGE_DOS_HEADER:\n");
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x00, "WORD", "e_magic", idh->e_magic);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x02, "WORD", "e_cblp", idh->e_cblp);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x04, "WORD", "e_cp", idh->e_cp);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x06, "WORD", "e_crlc", idh->e_crlc);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x08, "WORD", "e_cparhdr", idh->e_cparhdr);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x0a, "WORD", "e_minalloc", idh->e_minalloc);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x0c, "WORD", "e_maxalloc", idh->e_maxalloc);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x0e, "WORD", "e_ss", idh->e_ss);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x10, "WORD", "e_sp", idh->e_sp);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x12, "WORD", "e_csum", idh->e_csum);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x14, "WORD", "e_ip", idh->e_ip);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x16, "WORD", "e_cs", idh->e_cs);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x18, "WORD", "e_lfarlc", idh->e_lfarlc);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x1a, "WORD", "e_ovno", idh->e_ovno);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x1c, "WORD", "e_res[0]", idh->e_res[0]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x1e, "WORD", "e_res[1]", idh->e_res[1]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x20, "WORD", "e_res[2]", idh->e_res[2]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x22, "WORD", "e_res[3]", idh->e_res[3]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x24, "WORD", "e_oemid", idh->e_oemid);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x26, "WORD", "e_oeminfo", idh->e_oeminfo);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x28, "WORD", "e_res2[0]", idh->e_res2[0]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x2a, "WORD", "e_res2[1]", idh->e_res2[1]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x2c, "WORD", "e_res2[2]", idh->e_res2[2]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x2e, "WORD", "e_res2[3]", idh->e_res2[3]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x30, "WORD", "e_res2[4]", idh->e_res2[4]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x32, "WORD", "e_res2[5]", idh->e_res2[5]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x34, "WORD", "e_res2[6]", idh->e_res2[6]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x36, "WORD", "e_res2[7]", idh->e_res2[7]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x38, "WORD", "e_res2[8]", idh->e_res2[8]);
	printf("  0x%02x  %-8s%-12s: 0x%04x\n", 0x4a, "WORD", "e_res2[9]", idh->e_res2[9]);
	printf("  0x%02x  %-8s%-12s: 0x%08x\n", 0x3c, "DWORD", "e_lfanew", idh->e_lfanew);

	inh = (PIMAGE_NT_HEADERS)((PBYTE)PEFile->ZeroFileOffsetPointer + idh->e_lfanew);

	if (inh->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", inh->Signature, IMAGE_NT_SIGNATURE);
		return;
	}
	printf("\nIMAGE_NT_HEADERS:\n");
	printf("  0x%02x  %-25s%-16s: 0x%08x\n", 0x00, "DWORD", "Signature", inh->Signature);
	printf("  0x%02x  %-25s%-16s: 0x%08x\n", 0x04, "IMAGE_FILE_HEADER", "FileHeader", inh->FileHeader);
	printf("  0x%02x  %-25s%-16s: 0x%08x\n", 0x18, "IMAGE_OPTIONAL_HEADER", "OptionalHeader", inh->OptionalHeader);

	printf("\nIMAGE_FILE_HEADER:\n");
	printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x00, "WORD", "Machine", inh->FileHeader.Machine);
	printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x02, "WORD", "NumberOfSections", inh->FileHeader.NumberOfSections);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x04, "DWORD", "TimeDateStamp", inh->FileHeader.TimeDateStamp);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x08, "DWORD", "PointerToSymbolTable", inh->FileHeader.PointerToSymbolTable);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x0c, "DWORD", "NumberOfSymbols", inh->FileHeader.NumberOfSymbols);
	printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x10, "WORD", "SizeOfOptionalHeader", inh->FileHeader.SizeOfOptionalHeader);
	printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x12, "WORD", "Characteristics", inh->FileHeader.Characteristics);

	printf("\nIMAGE_OPTIONAL_HEADER:\n");
	if (inh->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", inh->OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC);
		return;
	}
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x00, "WORD", "Magic", inh->OptionalHeader.Magic);
	printf("  0x%02x  %-8s%-32s: 0x%02x\n", 0x02, "BYTE", "MajorLinkerVersion", inh->OptionalHeader.MajorLinkerVersion);
	printf("  0x%02x  %-8s%-32s: 0x%02x\n", 0x03, "BYTE", "MinorLinkerVersion", inh->OptionalHeader.MinorLinkerVersion);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x04, "DWORD", "SizeOfCode", inh->OptionalHeader.SizeOfCode);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x08, "DWORD", "SizeOfInitializedData", inh->OptionalHeader.SizeOfInitializedData);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x0c, "DWORD", "SizeOfUninitializedData", inh->OptionalHeader.SizeOfUninitializedData);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x10, "DWORD", "AddressOfEntryPoint", inh->OptionalHeader.AddressOfEntryPoint);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x14, "DWORD", "BaseOfCode", inh->OptionalHeader.BaseOfCode);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x18, "DWORD", "BaseOfData", inh->OptionalHeader.BaseOfData);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x1c, "DWORD", "ImageBase", inh->OptionalHeader.ImageBase);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x20, "DWORD", "SectionAlignment", inh->OptionalHeader.SectionAlignment);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x24, "DWORD", "FileAlignment", inh->OptionalHeader.FileAlignment);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x28, "WORD", "MajorOperatingSystemVersion", inh->OptionalHeader.MajorOperatingSystemVersion);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x2a, "WORD", "MinorOperatingSystemVersion", inh->OptionalHeader.MinorOperatingSystemVersion);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x2c, "WORD", "MajorImageVersion", inh->OptionalHeader.MajorImageVersion);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x2e, "WORD", "MinorImageVersion", inh->OptionalHeader.MinorImageVersion);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x30, "WORD", "MajorSubsystemVersion", inh->OptionalHeader.MajorSubsystemVersion);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x32, "WORD", "MinorSubsystemVersion", inh->OptionalHeader.MinorSubsystemVersion);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x34, "DWORD", "Win32VersionValue", inh->OptionalHeader.Win32VersionValue);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x38, "DWORD", "SizeOfImage", inh->OptionalHeader.SizeOfImage);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x3c, "DWORD", "SizeOfHeaders", inh->OptionalHeader.SizeOfHeaders);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x40, "DWORD", "CheckSum", inh->OptionalHeader.CheckSum);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x44, "WORD", "Subsystem", inh->OptionalHeader.Subsystem);
	printf("  0x%02x  %-8s%-32s: 0x%04x\n", 0x46, "WORD", "DllCharacteristics", inh->OptionalHeader.DllCharacteristics);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x48, "DWORD", "SizeOfStackReserve", inh->OptionalHeader.SizeOfStackReserve);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x4c, "DWORD", "SizeOfStackCommit", inh->OptionalHeader.SizeOfStackCommit);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x50, "DWORD", "SizeOfHeapReserve", inh->OptionalHeader.SizeOfHeapReserve);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x54, "DWORD", "SizeOfHeapCommit", inh->OptionalHeader.SizeOfHeapCommit);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x58, "DWORD", "LoaderFlags", inh->OptionalHeader.LoaderFlags);
	printf("  0x%02x  %-8s%-32s: 0x%08x\n", 0x5c, "DWORD", "NumberOfRvaAndSizes", inh->OptionalHeader.NumberOfRvaAndSizes);
	printf("  0x%02x  %s %s\n", 0x60, "IMAGE_DATA_DIRECTORY", "DataDirectory[16]:");

	printf("    IMAGE_DIRECTORY_ENTRY_EXPORT:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_IMPORT:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_RESOURCE:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_EXCEPTION:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_SECURITY:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_BASERELOC:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_DEBUG:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_ARCHITECTURE:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_ARCHITECTURE].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_GLOBALPTR:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_TLS:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_IAT:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size);
	printf("    IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:\n");
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x00, "DWORD", "VirtualAddress", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress);
	printf("      0x%02x  %-8s%-16s: 0x%08x\n", 0x04, "DWORD", "Size", inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size);

	ishs = (PIMAGE_SECTION_HEADER)((PBYTE)inh + sizeof (inh) + sizeof (IMAGE_FILE_HEADER) + inh->FileHeader.SizeOfOptionalHeader);

	printf("\n");
	for (i = 0; i < inh->FileHeader.NumberOfSections; ++i)
	{
		printf("IMAGE_SECTION_HEADER #%d:\n", i);
		printf("  0x%02x  %-8s%-25s: %s\n", 0x00, "PBYTE", "Name", ishs[i].Name);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x08, "DWORD", "VirtualSize", ishs[i].Misc.VirtualSize);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x0c, "DWORD", "VirtualAddress", ishs[i].VirtualAddress);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x10, "DWORD", "SizeOfRawData", ishs[i].SizeOfRawData);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x14, "DWORD", "PointerToRawData", ishs[i].PointerToRawData);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x18, "DWORD", "PointerToRelocations", ishs[i].PointerToRelocations);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x1c, "DWORD", "PointerToLinenumbers", ishs[i].PointerToLinenumbers);
		printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x20, "WORD", "NumberOfRelocations", ishs[i].NumberOfRelocations);
		printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x22, "WORD", "NumberOfLinenumbers", ishs[i].NumberOfLinenumbers);
		printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x24, "DWORD", "Characteristics", ishs[i].Characteristics);
	}

	return;
}

VOID PrintExportsRaw(PEXECUTABLEFILE PEFile)
{
	PIMAGE_DOS_HEADER idh;
	PIMAGE_NT_HEADERS inh;
	PIMAGE_EXPORT_DIRECTORY ied;
	PIMAGE_SECTION_HEADER ishs;
    DWORD i;

	idh = (PIMAGE_DOS_HEADER)PEFile->ZeroFileOffsetPointer;

	if (idh->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", idh->e_magic, IMAGE_DOS_SIGNATURE);
		return;
	}
	inh = (PIMAGE_NT_HEADERS)((PBYTE)PEFile->ZeroFileOffsetPointer + idh->e_lfanew);
	if (inh->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", inh->Signature, IMAGE_NT_SIGNATURE);
		return;
	}

	ishs = (PIMAGE_SECTION_HEADER)((PBYTE)inh + sizeof (inh) + sizeof (IMAGE_FILE_HEADER) + inh->FileHeader.SizeOfOptionalHeader);
	if (inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0)
	{
		printf("\nNO exports\n");
		return;
	}
	ied = (PIMAGE_EXPORT_DIRECTORY)RelativeVirtualAddressToFileAddress(
		inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
		ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);

	printf("\nIMAGE_EXPORT_DIRECTORY:\n");
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x00, "DWORD", "Characteristics", ied->Characteristics);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x04, "DWORD", "TimeDateStamp", ied->TimeDateStamp);
	printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x08, "WORD", "MajorVersion", ied->MajorVersion);
	printf("  0x%02x  %-8s%-25s: 0x%04x\n", 0x0a, "WORD", "MinorVersion", ied->MinorVersion);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x0c, "DWORD", "Name", ied->Name);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x10, "DWORD", "Base", ied->Base);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x14, "DWORD", "NumberOfFunctions", ied->NumberOfFunctions);
	printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x18, "DWORD", "NumberOfNames", ied->NumberOfNames);
    {
        PDWORD aofs;
        PDWORD nofs;
        PWORD noos;

        printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x1c, "DWORD", "AddressOfFunctions", ied->AddressOfFunctions);

        aofs = (PDWORD) RelativeVirtualAddressToFileAddress(
            ied->AddressOfFunctions, ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);
        nofs = (PDWORD) RelativeVirtualAddressToFileAddress(
            ied->AddressOfNames, ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);
        noos = (PWORD) RelativeVirtualAddressToFileAddress(
            ied->AddressOfNameOrdinals, ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);

        for (i = 0; i < ied->NumberOfFunctions; ++i)
        {
            printf("    0x%02x  DWORD   : 0x%08x\n", 0x04 * i, aofs[i]);
        }

        printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x20, "DWORD", "AddressOfNames", ied->AddressOfNames);
        for (i = 0; i < ied->NumberOfNames; ++i)
        {
            PCHAR namePointer = (PCHAR) RelativeVirtualAddressToFileAddress(
                nofs[i], ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);

            printf("    0x%02x  DWORD   : 0x%08x = %-25s\n", 0x04 * i, nofs[i], namePointer);
        }

        printf("  0x%02x  %-8s%-25s: 0x%08x\n", 0x24, "DWORD", "AddressOfNameOrdinals", ied->AddressOfNameOrdinals);
        for (i = 0; i < ied->NumberOfNames; ++i)
        {
            printf("    0x%02x  WORD    : % 2d\n", 0x04 * i, noos[i]);
        }
    }

    return;
}

VOID PrintImportsRaw(PEXECUTABLEFILE PEFile)
{
	PIMAGE_DOS_HEADER idh;
	PIMAGE_NT_HEADERS inh;
    PIMAGE_IMPORT_DESCRIPTOR iid;
	PIMAGE_SECTION_HEADER ishs;
    DWORD i;

	idh = (PIMAGE_DOS_HEADER)PEFile->ZeroFileOffsetPointer;

	if (idh->e_magic != IMAGE_DOS_SIGNATURE)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", idh->e_magic, IMAGE_DOS_SIGNATURE);
		return;
	}
	inh = (PIMAGE_NT_HEADERS)((PBYTE)PEFile->ZeroFileOffsetPointer + idh->e_lfanew);
	if (inh->Signature != IMAGE_NT_SIGNATURE)
	{
		printf("[ERROR] Incorrect signature: 0x%08x != 0x%08x\n", inh->Signature, IMAGE_NT_SIGNATURE);
		return;
	}

	ishs = (PIMAGE_SECTION_HEADER)((PBYTE)inh + sizeof (inh) + sizeof (IMAGE_FILE_HEADER) + inh->FileHeader.SizeOfOptionalHeader);
	if (inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
	{
		printf("\nNO imports\n");
		return;
	}
    iid = (PIMAGE_IMPORT_DESCRIPTOR)RelativeVirtualAddressToFileAddress(
        inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
		ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);

    printf("\n");
    for (i = 0; ((PDWORD)iid)[0] != 0; ++i, ++iid)
    {
        printf("IMAGE_IMPORT_DESCRIPTOR #%d:\n", i);
        printf("  0x%02x  %-20s%-20s: 0x%08x\n", 0x00, "PIMAGE_THUNK_DATA", "OriginalFirstThunk", iid->OriginalFirstThunk);
        printf("  0x%02x  %-20s%-20s: 0x%08x\n", 0x04, "DWORD", "TimeDateStamp", iid->TimeDateStamp);
        printf("  0x%02x  %-20s%-20s: 0x%08x\n", 0x08, "DWORD", "ForwarderChain", iid->ForwarderChain);
        {
            PCHAR namePointer = (PCHAR) RelativeVirtualAddressToFileAddress(
                iid->Name, ishs, inh->FileHeader.NumberOfSections, (DWORD)PEFile->ZeroFileOffsetPointer);
            printf("  0x%02x  %-20s%-20s: 0x%08x = %s\n", 0x0c, "DWORD", "Name", iid->Name, namePointer);
        }
        printf("  0x%02x  %-20s%-20s: 0x%08x\n", 0x10, "PIMAGE_THUNK_DATA", "FirstThunk", iid->FirstThunk);
    }

    if (!i) printf("NO imports\n");

    return;
}
